22. Loading Indicator
Loading Indicator
Question:
Start Quiz:
Solution:
Code changes
First, add the ProgressBar view to the layout. You could have referred to the Common Android Views Cheat Sheet to see an example of a ProgressBar in XML. I added the view as the last child of the RelativeLayout, so that it would appear on top of the other children views. The height and width are set as “wrap_content” and the view is centered in the middle of the screen. The style “@style/Widget.AppCompat.ProgressBar” makes the ProgressBar appear as a circular loading indicator.
In earthquake_activity.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:dividerHeight="0dp"/>
<!-- Empty view is only visible when the list has no items. -->
<TextView
android:id="@+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textAppearance="?android:textAppearanceMedium"/>
<!-- Loading indicator is only shown before the first load -->
<ProgressBar
android:id="@+id/loading_indicator"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
In EarthquakeActivity.java, hide the loading indicator (by setting visibility to View.GONE) after the first load is completed - when onLoadFinished() is called.
In EarthquakeActivity.java:
@Override
public void onLoadFinished(Loader<List<Earthquake>> loader, List<Earthquake> earthquakes) {
// Hide loading indicator because the data has been loaded
View loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
// Set empty state text to display "No earthquakes found."
mEmptyStateTextView.setText(R.string.no_earthquakes);
// Clear the adapter of previous earthquake data
mAdapter.clear();
// If there is a valid list of {@link Earthquake}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (earthquakes != null && !earthquakes.isEmpty()) {
mAdapter.addAll(earthquakes);
}
}
Run the app on a device and the loading indicator should appear if the network call takes a long time. Sometimes, the internet connection may be so fast that the loading indicator is not visible on screen for enough time for the human eye to catch it.
Testing
Hence, as detailed in the notes below the quiz, perform the following 2 tests to check that the loading indicator will lead to the list of earthquake results OR that the loading indicator will lead to the empty view.
Test #1: Force the background thread to sleep for 2 seconds
To force the background thread to sleep for 2 seconds, we are temporarily simulating a very slow network response time. We are “pretending” that it took a long time to fetch the response. That allows us to see the loading spinner on the screen for a little longer than it normally would appear for.
In the QueryUtils.java file, within the fetchEarthquakeData() method, add this snippet of code at the top of the method. Leave the rest of the code in the method as-is. We are forcing the background thread to pause execution and wait for 2 seconds (which is 2000 milliseconds), before proceeding to execute the rest of lines of code in this method. If you try to add the Thread.sleep(2000); method call by itself, Android Studio will complain that there is an uncaught exception, so we need to surround that statement with a try/catch block.
In QueryUtils.java:
public static List<Earthquake> fetchEarthquakeData(String requestUrl) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
…
}
Now when you run the app, you should see the loading indicator for 2 seconds, and then the list of earthquakes appear.
Test #2: Pretend like no results came back from the server
In the EarthquakeActivity onLoadFInished method, temporarily comment out the line of code where the earthquake data is added to the adapter. This will make it seem like there are no earthquakes in the list, and should trigger the empty state.
In QueryUtils.java:
@Override
public void onLoadFinished(Loader<List<Earthquake>> loader, List<Earthquake> earthquakes) {
...
// If there is a valid list of {@link Earthquake}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (earthquakes != null && !earthquakes.isEmpty()) {
// mAdapter.addAll(earthquakes);
}
}
Now when you run the app, you should see the loading indicator for 2 seconds, and then the empty state saying “No earthquakes found.”
The code diff for this checkpoint is located here.
INSTRUCTOR NOTE:
Material Design Progress & Activity
Hint #1: See example of ProgressBar view in the Common Android Views Cheat Sheet.
Hint #2: Perform the following 2 tests to check that the loading indicator will lead to the list of earthquake results OR that the loading indicator will lead to the empty view.
Test #1: Force the background thread to sleep for 2 seconds
To force the background thread to sleep for 2 seconds, we are temporarily simulating a very slow network response time. We are “pretending” that it took a long time to fetch the response. That allows us to see the loading spinner on the screen for a little longer than it normally would appear for.
In the QueryUtils.java file, within the fetchEarthquakeData() method, add this snippet of code at the top of the method. Leave the rest of the code in the method as-is. We are forcing the background thread to pause execution and wait for 2 seconds (which is 2000 milliseconds), before proceeding to execute the rest of lines of code in this method. If you try to add the Thread.sleep(2000); method call by itself, Android Studio will complain that there is an uncaught exception, so we need to surround that statement with a try/catch block.
In QueryUtils.java:
public static List<Earthquake> fetchEarthquakeData(String requestUrl) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
…
}
Now when you run the app, you should see the loading indicator for 2 seconds, and then the list of earthquakes appear.
Test #2: Pretend like no results came back from the server
In the EarthquakeActivity onLoadFInished method, temporarily comment out the line of code where the earthquake data is added to the adapter. This will make it seem like there are no earthquakes results to show.
In QueryUtils.java:
@Override
public void onLoadFinished(Loader<List<Earthquake>> loader, List<Earthquake> earthquakes) {
...
// If there is a valid list of {@link Earthquake}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (earthquakes != null && !earthquakes.isEmpty()) {
// mAdapter.addAll(earthquakes);
}
}
Now when you run the app, you should see the loading indicator for 2 seconds, and then the empty state saying “No earthquakes found.”